package com.example.client.config;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.example.client.handlers.ClientHandler;
import com.example.common.codec.NettyMessage;
import com.example.common.codec.NettyMessageDecode;
import com.example.common.codec.NettyMessageEncode;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 582895699@qq.com
 * @Desctription: TODO
 * @Date: Created in 2021/11/28 22:53
 */
@Slf4j
@Component
public class NettyClient {

    public static final String SERVER_HOST = "127.0.0.1";
    public static final Integer SERVER_PORT = 8888;

    public final EventLoopGroup group = new NioEventLoopGroup();


    @Resource
    private ClientHandler clientHandler;

    public Channel channel;

    @PostConstruct
    public void init() {

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .remoteAddress(SERVER_HOST, SERVER_PORT)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new ChannelInitializer<Channel>() {

                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new NettyMessageEncode());
                        pipeline.addLast(new NettyMessageDecode());
                        pipeline.addLast(clientHandler);
                    }
                });
        ChannelFuture channelFuture = bootstrap.connect().syncUninterruptibly();
        if (channelFuture.isSuccess()) {
            channel = channelFuture.channel();
            log.info("连接成功;channelId:{}", channel.id());
            return;
        }
        reconnect();

    }


    public void reconnect() {
        group.schedule(() -> {
            log.info("客户端开始重连");
            try {
                init();
            } catch (Exception e) {
                log.warn("重连失败，Exception:{}", ExceptionUtil.stacktraceToString(e));
            }
        }, 10, TimeUnit.SECONDS);
    }

    public void send(String type, String msg) {
        if (Objects.isNull(channel)) {
            log.warn("channel is null");
            return;
        }
        if (!channel.isActive()) {
            log.warn("channel is not active");
            reconnect();
            return;
        }
        Map<String, String> map = new HashMap<>();
        map.put("account", msg);
        NettyMessage message = new NettyMessage(type, map);
        channel.writeAndFlush(message);
    }

    @PreDestroy
    public void shutDown() {
        if (Objects.isNull(channel)) {
            return;
        }
        log.info("客户端执行[shutDown]");
        group.shutdownGracefully();
    }
}
